home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgramD2.iso / Borland / Borland C++ V5.02 / CALC.PAK / CALC.CPP next >
C/C++ Source or Header  |  1997-05-06  |  8KB  |  409 lines

  1. //----------------------------------------------------------------------------
  2. // ObjectWindows
  3. // Copyright (c) 1991, 1995 by Borland International, All Rights Reserved
  4. //
  5. //  Sample example implementing a Calculator with ObjectWindows
  6. //----------------------------------------------------------------------------
  7. #include <owl/pch.h>
  8. #include <owl/applicat.h>
  9. #include <owl/dc.h>
  10. #include <owl/dialog.h>
  11. #include <owl/framewin.h>
  12. #include <services/cstring.h>
  13. #include <ctype.h>
  14. #include <math.h>
  15. #include <stdio.h>
  16. #include <stdlib.h>
  17.  
  18. const char AppName[] = "Calc";      // Name of application
  19. const int DisplayDigits = 15;       // Number of digits in calc. display
  20. const int ID_DISPLAY = 400;         // ID of static control used as display
  21.  
  22. // Calculator state
  23. //
  24. enum TCalcState { 
  25.   CS_FIRST, 
  26.   CS_VALID, 
  27.   CS_ERROR
  28. };  
  29.  
  30. // Calculator dialog window object
  31. //
  32. class TCalc : public TDialog {
  33.   public:
  34.     TCalcState  CalcStatus;
  35.     char        Operator;
  36.     char        Number[DisplayDigits + 1];
  37.     bool        Negative;
  38.     double      Operand;
  39.     TBrush      BlueBrush;
  40.  
  41.     TCalc();
  42.  
  43.     void          FlashButton(char key);
  44.     void          Error();
  45.  
  46.     void          SetDisplay(double r);
  47.     void          GetDisplay(double& r);
  48.     virtual void  UpdateDisplay();
  49.  
  50.     void          CheckFirst();
  51.     void          InsertKey(char key);
  52.     void          CalcKey(char key);
  53.     void          Clear();
  54.  
  55.   protected:
  56.  
  57.     // Override virtual handlers of WM_COMMAND and WM_PAINT respectively
  58.     //
  59.     LRESULT       EvCommand(uint, HWND, uint);
  60.     void          EvPaint();
  61.  
  62.     // Message response functions
  63.     //
  64.     HBRUSH        EvCtlColor(HDC, HWND hWndChild, uint ctlType);
  65.  
  66.   DECLARE_RESPONSE_TABLE(TCalc);
  67. };
  68.  
  69. DEFINE_RESPONSE_TABLE1(TCalc, TDialog)
  70.   EV_WM_PAINT,
  71.   EV_WM_CTLCOLOR,
  72. END_RESPONSE_TABLE;
  73.  
  74. //
  75. // Calculator constructor.  Create blue brush for calculator background,
  76. // and do a clear command.
  77. //
  78. TCalc::TCalc()
  79.   : TWindow((TWindow*)0),
  80.     TDialog(0, TResId("IDD_CALC")),
  81.     BlueBrush(TColor(0, 0, 255))
  82. {
  83.   Clear();
  84. }
  85.  
  86. //
  87. // Colorize the calculator. Allows background to show through corners of
  88. // buttons, uses yellow text on black background in the display, and sets
  89. // the dialog background to blue.
  90. //
  91. HBRUSH
  92. TCalc::EvCtlColor(HDC hDC, HWND hWndChild, uint ctlType)
  93. {
  94.   switch (ctlType) {
  95.     case CTLCOLOR_BTN:
  96.       SetBkMode(hDC, TRANSPARENT);
  97.       return (HBRUSH)GetStockObject(NULL_BRUSH);
  98.  
  99.     case CTLCOLOR_STATIC:
  100.       SetTextColor(hDC, TColor::LtYellow);
  101.       SetBkMode(hDC, TRANSPARENT);
  102.       return (HBRUSH)GetStockObject(BLACK_BRUSH);
  103.  
  104.     case CTLCOLOR_DLG:
  105.       SetBkMode(hDC, TRANSPARENT);
  106.       return (HBRUSH)BlueBrush;
  107.  
  108.     default:
  109.       return TDialog::EvCtlColor(hDC, hWndChild, ctlType);
  110.   }
  111. }
  112.  
  113. //
  114. // Even dialogs can have their backgrounds painted on.  This creates
  115. // a red ellipse over the blue background.
  116. //
  117. void
  118. TCalc::EvPaint()
  119. {
  120.   TBrush    redBrush(TColor(255, 0, 0));
  121.   TPaintDC  dc(*this);
  122.  
  123.   dc.SelectObject(redBrush);
  124.   dc.SelectStockObject(NULL_PEN);
  125.  
  126.   TRect clientRect = GetClientRect();
  127.   clientRect.bottom = clientRect.right;
  128.   clientRect.Offset(-clientRect.right/4, -clientRect.right/4);
  129.   dc.Ellipse(clientRect);
  130. }
  131.  
  132. //
  133. // Flash a button with the value of Key.  Looks exactly like a
  134. // click of the button with the mouse.
  135. //
  136. void
  137. TCalc::FlashButton(char key)
  138. {
  139.   if (key == 0x0D)
  140.      key = '=';  // Treat Enter like '='
  141.  
  142.   HWND button = GetDlgItem(toupper(key));
  143.  
  144.   if (button) {
  145.     ::SendMessage(button, BM_SETSTATE, 1, 0);
  146.  
  147.     for (int delay = 1; delay <= 30000; ++delay)
  148.       ;
  149.  
  150.     ::SendMessage(button, BM_SETSTATE, 0, 0);
  151.   }
  152. }
  153.  
  154. //
  155. // Here we handle all of the child id notifications (BN_CLICKED from the
  156. // buttons) and all accelerators at once rather than have separate response
  157. // table entries for each...
  158. //
  159. LRESULT
  160. TCalc::EvCommand(uint id, HWND hWndCtl, uint notifyCode)
  161. {
  162.   if (hWndCtl != 0 && notifyCode == BN_CLICKED)
  163.     CalcKey(char(id));  // button notification
  164.  
  165.   else if (hWndCtl == 0 && notifyCode == 1) {
  166.     //
  167.     // from an accelerator
  168.     //
  169.     FlashButton(char(id));
  170.     CalcKey(char(id));
  171.   }
  172.  
  173.   return TDialog::EvCommand(id, hWndCtl, notifyCode);
  174. }
  175.  
  176. //
  177. // Set Display text to the current value.
  178. //
  179. void
  180. TCalc::UpdateDisplay()
  181. {
  182.   char  str[DisplayDigits + 2];
  183.  
  184.   if (Negative)
  185.     strcpy(str, "-");
  186.  
  187.   else
  188.     str[0] = '\0';
  189.  
  190.   ::SetWindowText(GetDlgItem(ID_DISPLAY), strcat(str, Number));
  191. }
  192.  
  193. //
  194. // Clear the calculator.
  195. //
  196. void
  197. TCalc::Clear()
  198. {
  199.   CalcStatus = CS_FIRST;
  200.   strcpy(Number, "0");
  201.   Negative = false;
  202.   Operator = '=';
  203. }
  204.  
  205. void
  206. TCalc::Error()
  207. {
  208.   CalcStatus = CS_ERROR;
  209.   strcpy(Number, "Error");
  210.   Negative = false;
  211. }
  212.  
  213. void
  214. TCalc::SetDisplay(double r)
  215. {
  216.   char*  first;
  217.   char*  last;
  218.   int    charsToCopy;
  219.   char   str[64];
  220.  
  221.   //
  222.   // limit results of calculations to 7 digits to the right of the dec. point
  223.   //
  224.   r = (floor(r * 10000000L + .5)) / 10000000L;
  225.  
  226.   sprintf(str, "%0.10f", r);
  227.   first = str;
  228.   Negative = false;
  229.  
  230.   if (str[0] == '-') {
  231.     first++;
  232.     Negative = true;
  233.   }
  234.  
  235.   if (strlen(first) > DisplayDigits + 1 + 10 )
  236.     Error();
  237.  
  238.   else {
  239.     last = strchr(first, 0);
  240.  
  241.     while (last[-1] == '0')
  242.       --last;
  243.  
  244.     if (last[-1] == '.')
  245.       --last;
  246.  
  247.     charsToCopy = min(DisplayDigits + 1, int(last - first));
  248.     strncpy(Number, first, charsToCopy);
  249.     Number[charsToCopy] = 0;
  250.   }
  251. }
  252.  
  253. void
  254. TCalc::GetDisplay(double& r)
  255. {
  256.   r = atof(Number);
  257.  
  258.   if (Negative)
  259.     r = -r;
  260. }
  261.  
  262. void
  263. TCalc::CheckFirst()
  264. {
  265.   if (CalcStatus == CS_FIRST) {
  266.     CalcStatus = CS_VALID;
  267.     strcpy(Number, "0");
  268.     Negative = false;
  269.   }
  270. }
  271.  
  272. void
  273. TCalc::InsertKey(char key)
  274. {
  275.   int l = strlen(Number);
  276.  
  277.   if (l < DisplayDigits) {
  278.     Number[l] = key;
  279.     Number[l + 1] = 0;
  280.   }
  281. }
  282.  
  283. //
  284. // Process calculator key.
  285. //
  286. void
  287. TCalc::CalcKey(char key)
  288. {
  289.   key = (char)toupper(key);
  290.  
  291.   if (CalcStatus == CS_ERROR && key != 'C')
  292.     key = ' ';
  293.  
  294.   if (key >= '0' && key <= '9') {
  295.     CheckFirst();
  296.  
  297.     if (strcmp(Number, "0") == 0)
  298.       Number[0] = '\0';
  299.  
  300.     InsertKey(key);
  301.  
  302.   } else if (key == '+' || key == '-' || key == '*' ||
  303.              key == '/' || key == '=' || key == '%' || key == 0x0D) {
  304.  
  305.     if (CalcStatus == CS_VALID) {
  306.       CalcStatus = CS_FIRST;
  307.       double  r;
  308.       GetDisplay(r);
  309.  
  310.       if (key == '%') {
  311.         switch(Operator) {
  312.           case '+':
  313.           case '-':
  314.             r = Operand * r / 100;
  315.             break;
  316.  
  317.           case '*':
  318.           case '/':
  319.             r /= 100;
  320.             break;
  321.         }
  322.       }
  323.  
  324.       switch(Operator) {
  325.         case '+':
  326.           SetDisplay(Operand + r);
  327.           break;
  328.  
  329.         case '-':
  330.           SetDisplay(Operand - r);
  331.           break;
  332.  
  333.         case '*':
  334.           SetDisplay(Operand * r);
  335.           break;
  336.  
  337.         case '/':
  338.           if (r == 0)
  339.             Error();
  340.  
  341.           else
  342.             SetDisplay(Operand / r);
  343.           break;
  344.       }
  345.     }
  346.  
  347.     Operator = key;
  348.     GetDisplay(Operand);
  349.  
  350.   } else
  351.     switch(key) {
  352.       case '.':
  353.         CheckFirst();
  354.         if (!strchr(Number, '.'))
  355.           InsertKey(key);
  356.         break;
  357.  
  358.       case 0x8:
  359.         CheckFirst();
  360.         if (strlen(Number) == 1)
  361.           strcpy(Number, "0");
  362.         else
  363.           Number[strlen(Number) - 1] = '\0';
  364.         break;
  365.  
  366.       case '_':
  367.         Negative = !Negative;
  368.         break;
  369.  
  370.       case 'C':
  371.         Clear();
  372.         break;
  373.     }
  374.  
  375.   UpdateDisplay();
  376. }
  377.  
  378. //----------------------------------------------------------------------------
  379.  
  380. //
  381. // Calculator application object
  382. //
  383. class TCalcApp : public TApplication {
  384.   public:
  385.     TCalcApp(const char far* name) : TApplication(name) {}
  386.  
  387.     void   InitMainWindow();
  388. };
  389.  
  390. //
  391. // Create calculator as the application's main window.
  392. //
  393. void
  394. TCalcApp::InitMainWindow()
  395. {
  396.   TWindow* calcWin = new TCalc;
  397.   calcWin->Attr.AccelTable = "IDA_CALC";
  398.  
  399.   MainWindow = new TFrameWindow(0, Name, calcWin, true);
  400.   MainWindow->SetIcon(this, TResId("IDI_CALC"));
  401.   MainWindow->Attr.Style &= ~(WS_MAXIMIZEBOX | WS_THICKFRAME);
  402. }
  403.  
  404. int
  405. OwlMain(int /*argc*/, char* /*argv*/ [])
  406. {
  407.   return TCalcApp(AppName).Run();
  408. }
  409.